#include <cmath>
#include <cerrno>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include "VoltageTrace.h"

using namespace std;

VoltageTrace::VoltageTrace () {
    numSamples = 0;
    sampleRate = 0;
    traceDuration = 0.0;
    trace = NULL;
}

int VoltageTrace::loadFromFile (const char* const filename) {
    ifstream f(filename);
    if (!f) {
        HSLOG(stderr, "Error opening trace file %s\n", filename);
        return -1;
    }

    f >> numSamples;
    f >> sampleRate;
    if (!numSamples || !sampleRate) {
        HSLOG(stderr, "Error reading trace: malformed header\n");
        return -1;
    }
    HSLOG(stderr, "Number of samples: %lu \n", numSamples);
    HSLOG(stderr, "Sample rate: %lu Hz\n", sampleRate);

    trace = (trace_elt *)calloc(numSamples, sizeof(trace_elt));
    if (!trace) {
        HSLOG(stderr, "Unable to allocate memory for trace array.");
        return -1;
    }

    // read one <time,voltage> pair at a time
    trace_elt *te;
    char comma;
    unsigned long i = 0;
    for (; i < numSamples; ++i) {
        te = trace + i;
        f >> te->time >> comma >> te->value;
        if (f.eof())
            break;
    }
    f.close();
    if (i == numSamples) {
        HSLOG(stderr, "Loaded %lu samples from trace\n", numSamples);
    } else {
        HSLOG(stderr, "Error loading trace: read %lu of %lu samples\n", i,
                numSamples);
        return -1;
    }

    /*
    HSLOG(stderr, "First 10 samples:\n");
    for (unsigned int j = 0; j < 10; ++j) {
        HSLOG(stderr, "t=%lf, v=%lf\n", trace[j].time, trace[j].value);
    }
    */

    traceDuration = trace[numSamples-1].time - trace[0].time;
    HSLOG(stderr, "Trace duration: %lf seconds\n", traceDuration);

    return 0;
}

double VoltageTrace::getVoltage (double time) {
    double timeOffset;

    // translate time (in seconds) into a time offset from the beginning of the
    // trace.
    if (time < 0.0) {
        timeOffset = 0.0;
    } else if (time > traceDuration) {
        timeOffset -= floor(time / traceDuration) * traceDuration;
    } else {
        timeOffset = time;
    }

    // jump to the sample corresponding to that time.
    unsigned long sampleIndex = floor(time * sampleRate);
    if (sampleIndex < 0 || sampleIndex >= numSamples) {
        sampleIndex = 0; // start over
    }

    return lastVoltageReturned = trace[sampleIndex].value;
}

VoltageTrace::~VoltageTrace () {
}
